package com.lqg.bookLibrary.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.lqg.bookLibrary.common.core.domain.JsonResult;
import com.lqg.bookLibrary.common.myInterface.CurrentUser;
import com.lqg.bookLibrary.common.myInterface.CurrentUserPojo;
import com.lqg.bookLibrary.common.util.JwtUtils;
import com.lqg.bookLibrary.pojo.AvgScore;
import com.lqg.bookLibrary.pojo.Books;
import com.lqg.bookLibrary.pojo.Borrow;
import com.lqg.bookLibrary.pojo.Type;
import com.lqg.bookLibrary.service.IAvgScoreService;
import com.lqg.bookLibrary.service.IBooksService;
import com.lqg.bookLibrary.service.IBorrowService;
import com.lqg.bookLibrary.service.ITypeService;
import com.lqg.bookLibrary.service.recommend.BorrowedHistoryRecommend;
import com.lqg.bookLibrary.service.recommend.RateRecommend;
import com.lqg.bookLibrary.service.recommend.ThermalRecommend;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.net.http.HttpRequest;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/book")
@CrossOrigin
public class BookController {

    @Autowired
    JwtUtils jwtUtils;

    @Autowired
    private IBooksService booksService;

    @Autowired
    private IBorrowService borrowService;

    @Autowired
    private ITypeService typeService;


    @Autowired
    private BorrowedHistoryRecommend<Long, Long> borrowedHistoryRecommend;

    @Autowired
    private RateRecommend<Long, Long> rateRecommend;

    @Autowired
    private IAvgScoreService avgScoreService;

    @GetMapping("/detail/{bookId}")
    public JsonResult getBookDetail(@PathVariable Long bookId) {
        //System.out.println(bookId);
        Books one = booksService.lambdaQuery().eq(Books::getBookId, bookId).one();

        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(one));
        jsonObject.put("score",
                avgScoreService.lambdaQuery().eq(AvgScore::getBookId, bookId).one().getAvgScore()
        );

        return JsonResult.success(jsonObject);
    }

    @GetMapping("/well")
    public JsonResult getBookWell() {

        QueryWrapper<Borrow> wrapper = new QueryWrapper<>();
        QueryWrapper<Borrow> wrapper1 = wrapper.select("book_id, count(*) as num")
                .groupBy("book_id")
                .orderByDesc("num")
                .last("limit 20");

        List<Map<String, Object>> maps =
                borrowService.listMaps(wrapper1);

        List<Books> list1 = booksService.lambdaQuery().in(Books::getBookId,
                maps.stream().map(x-> x.get("book_id")).collect(Collectors.toList())
                ).list();

        List<AvgScore> avgScoreList = avgScoreService.lambdaQuery().in(AvgScore::getBookId,
                maps.stream().map(x -> x.get("book_id")).collect(Collectors.toList())
        ).list();

        List<JSONObject> jsonObjectList = list1.stream()
                .map(x -> {
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(x));
                    jsonObject.put("score",
                            avgScoreList.stream().filter(y -> Objects.equals(y.getBookId(), x.getBookId())).findFirst().get().getAvgScore()
                            );
                    return jsonObject;
                }).collect(Collectors.toList());

        return JsonResult.success(jsonObjectList);
    }


    @GetMapping("/type/first/{typeId}")
    public JsonResult getBookByTypeIdFirst(@PathVariable int typeId) {

        Type one = typeService.lambdaQuery().eq(Type::getTypeId, typeId).one();

        List<Type> list = typeService.lambdaQuery().eq(Type::getFatherId, typeId).list();

        List<Books> list1 = booksService.lambdaQuery().in(Books::getTypeId,
                        list.stream().map(x -> x.getTypeId()).collect(Collectors.toList()))
                .orderByDesc(Books::getCreatedAt)
                .last("limit 20")
                .list();

        List<AvgScore> avgScoreList = avgScoreService.lambdaQuery().in(AvgScore::getBookId,
                list1.stream().map(x -> x.getBookId()).collect(Collectors.toList())
        ).list();

        List<JSONObject> jsonObjectList = list1.stream()
                .map(x -> {
                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(x));
                    jsonObject.put("score",
                            avgScoreList.stream().filter(y -> Objects.equals(y.getBookId(), x.getBookId())).findFirst().get().getAvgScore()
                    );
                    return jsonObject;
                }).collect(Collectors.toList());

        return JsonResult.success(jsonObjectList);
    }

    @GetMapping("/type/second/{typeId}")
    public JsonResult getBookByTypeIdSecond(@PathVariable int typeId) {

        List<Books> list1 = booksService.lambdaQuery().eq(Books::getTypeId, typeId)
                .orderByDesc(Books::getCreatedAt)
                .last("limit 20")
                .list();

        return JsonResult.success(list1);
    }

    @GetMapping("/condition/{recType}/{bookTypeId}/{scoreMax}")
    public JsonResult getBookByCondition(@PathVariable int recType,
                                         @PathVariable int bookTypeId,
                                         @PathVariable int scoreMax,
                                         @CurrentUser CurrentUserPojo userPojo
                                         ) {

        Long userId = userPojo.getUserId();
        if (recType == 2 || recType == 3) {
            List<Long> recommendBooks = null;
            if (recType == 2){
                // 基于历史推荐
                recommendBooks = borrowedHistoryRecommend.recommendBooks(userId);
            }else {
                // 基于评分推荐
                recommendBooks = rateRecommend.recommendBooks(userId);
            }

            List<Long> list = new ArrayList<>();
            list = avgScoreService.lambdaQuery()
                    .in(AvgScore::getBookId, recommendBooks)
                    .le(AvgScore::getAvgScore, scoreMax)
                    .list()
                    .stream().map(x -> x.getBookId()).collect(Collectors.toList());
            ;
            List<Books> list1 = booksService.lambdaQuery()
                    .in(Books::getBookId, list)
                    .eq(Books::getTypeId, bookTypeId)
                    //.last("limit 20")
                    .list();

            List<AvgScore> avgScoreList = avgScoreService.lambdaQuery().in(AvgScore::getBookId,
                    list1.stream().map(x -> x.getBookId()).collect(Collectors.toList())
            ).list();

            List<JSONObject> jsonObjectList = list1.stream()
                    .map(x -> {
                        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(x));
                        jsonObject.put("score",
                                avgScoreList.stream()
                                        .filter(y -> Objects.equals(y.getBookId(), x.getBookId())).findFirst().get().getAvgScore()
                        );
                        return jsonObject;
                    }).collect(Collectors.toList());

            return JsonResult.success(jsonObjectList);

        }else {
            // 不推荐
            List<Long> collect = avgScoreService.lambdaQuery()
                    .le(AvgScore::getAvgScore, scoreMax)
                    .list()
                    .stream().map(x -> x.getBookId()).collect(Collectors.toList());
            List<Books> list = booksService.lambdaQuery()
                    .in(Books::getBookId, collect)
                    .eq(Books::getTypeId, bookTypeId)
                    .last("limit 20")
                    .list();

            List<AvgScore> avgScoreList = avgScoreService.lambdaQuery().in(AvgScore::getBookId,
                    list.stream().map(x -> x.getBookId()).collect(Collectors.toList())
            ).list();

            List<JSONObject> jsonObjectList = list.stream()
                    .map(x -> {
                        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(x));
                        jsonObject.put("score",
                                avgScoreList.stream()
                                        .filter(y -> Objects.equals(y.getBookId(), x.getBookId())).findFirst().get().getAvgScore()
                        );
                        return jsonObject;
                    }).collect(Collectors.toList());

            List<JSONObject> result = jsonObjectList.stream().sorted(
                    Comparator.comparingDouble(x -> Double.parseDouble(x.get("score").toString()))
            ).collect(Collectors.toList());

            Collections.reverse(result);

            return JsonResult.success(result);
        }
    }


}
